package com.automannn.cas.practice.casServerCustomWebflow;

import org.apereo.cas.authentication.*;
import org.apereo.cas.authentication.adaptive.AdaptiveAuthenticationPolicy;
import org.apereo.cas.authentication.adaptive.DefaultAdaptiveAuthenticationPolicy;
import org.apereo.cas.authentication.adaptive.geo.GeoLocationResponse;
import org.apereo.cas.authentication.adaptive.geo.GeoLocationService;
import org.apereo.cas.authentication.adaptive.intel.IPAddressIntelligenceService;
import org.apereo.cas.authentication.adaptive.intel.RestfulIPAddressIntelligenceService;
import org.apereo.cas.authentication.principal.DefaultPrincipalFactory;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.logout.DefaultLogoutExecutionPlan;
import org.apereo.cas.logout.DefaultLogoutManager;
import org.apereo.cas.logout.LogoutExecutionPlan;
import org.apereo.cas.logout.LogoutManager;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.support.geo.AbstractGeoLocationService;
import org.apereo.cas.ticket.TicketFactory;
import org.apereo.cas.ticket.factory.DefaultTicketFactory;
import org.apereo.cas.ticket.registry.DefaultTicketRegistry;
import org.apereo.cas.ticket.registry.DefaultTicketRegistrySupport;
import org.apereo.cas.ticket.registry.TicketRegistry;
import org.apereo.cas.ticket.registry.TicketRegistrySupport;
import org.apereo.cas.util.cipher.ProtocolTicketCipherExecutor;
import org.apereo.cas.util.crypto.CipherExecutor;
import org.apereo.cas.web.flow.DefaultSingleSignOnParticipationStrategy;
import org.apereo.cas.web.flow.SingleSignOnParticipationStrategy;
import org.apereo.cas.web.flow.resolver.CasDelegatingWebflowEventResolver;
import org.apereo.cas.web.flow.resolver.CasWebflowEventResolver;
import org.apereo.cas.web.flow.resolver.impl.CasWebflowEventResolutionConfigurationContext;
import org.apereo.cas.web.flow.resolver.impl.DefaultCasDelegatingWebflowEventResolver;
import org.apereo.cas.web.flow.resolver.impl.ServiceTicketRequestWebflowEventResolver;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.net.InetAddress;

/**
 * @author chenkh
 * @time 2021/12/16 20:30
 */
@Component
public class CasConfiguration implements ApplicationContextAware {
   private ApplicationContext applicationContext;


   @Autowired
  private ServicesManager servicesManager;

    @Bean
    public LogoutExecutionPlan logoutExecutionPlan(){
        LogoutExecutionPlan plan = new DefaultLogoutExecutionPlan();
        return plan;
    }

    @Bean
    public TicketRegistry ticketRegistry(){
        return new DefaultTicketRegistry();
    }

    @Bean
    public TicketFactory defaultTicketFactory(){
        return new DefaultTicketFactory();
    }

    @Bean
    public DefaultPrincipalFactory principalFactory(){
        return new DefaultPrincipalFactory();
    }

    @Bean
    public CipherExecutor protocolTicketCipherExecutor(){
        return new ProtocolTicketCipherExecutor();
    }

    @Bean
    public TicketRegistrySupport defaultTicketRegistrySupport(TicketRegistry ticketRegistry){
        return new DefaultTicketRegistrySupport(ticketRegistry);
    }

    @Bean
    public SingleSignOnParticipationStrategy singleSignOnParticipationStrategy(TicketRegistrySupport ticketRegistrySupport, AuthenticationServiceSelectionPlan authenticationServiceSelectionPlan){
        return new DefaultSingleSignOnParticipationStrategy(servicesManager,true,true,ticketRegistrySupport,authenticationServiceSelectionPlan);
    }

    @Bean
    public AuthenticationEventExecutionPlan authenticationEventExecutionPlan(){
        return  new DefaultAuthenticationEventExecutionPlan();
    }

    @Bean
    public LogoutManager logoutManager(LogoutExecutionPlan logoutExecutionPlan){
        //单点登出回调
        return new DefaultLogoutManager(true,logoutExecutionPlan);
    }

    @Bean
    public CasWebflowEventResolver serviceTicketRequestWebflowEventResolver(CasWebflowEventResolutionConfigurationContext context){
        return new ServiceTicketRequestWebflowEventResolver(context);
    }

    @Bean
    public CasWebflowEventResolver rankedAuthenticationProviderWebflowEventResolver(CasWebflowEventResolutionConfigurationContext context){
        return new ServiceTicketRequestWebflowEventResolver(context);
    }

    @Bean
    public CasDelegatingWebflowEventResolver initialAuthenticationAttemptWebflowEventResolver(CasWebflowEventResolutionConfigurationContext context,CasWebflowEventResolver serviceTicketRequestWebflowEventResolver){
        return new DefaultCasDelegatingWebflowEventResolver(context,serviceTicketRequestWebflowEventResolver);
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationEventExecutionPlan executionPlan){
        return new PolicyBasedAuthenticationManager(executionPlan,true,this.applicationContext);
    }

    @Bean
    public AuthenticationTransactionManager authenticationTransactionManager(AuthenticationManager authenticationManager){
        return new DefaultAuthenticationTransactionManager(this.applicationContext,authenticationManager);
    }

    @Bean
    public PrincipalElectionStrategy principalElectionStrategy(){
        return new DefaultPrincipalElectionStrategy();
    }

    @Bean
    public AuthenticationSystemSupport defaultAuthenticationSystemSupport(AuthenticationTransactionManager transactionManager,PrincipalElectionStrategy strategy){
        return new DefaultAuthenticationSystemSupport(transactionManager,strategy);
    }

    @Bean
    public GeoLocationService geoLocationService(){
        return new AbstractGeoLocationService(){
            @Override
            public GeoLocationResponse locate(InetAddress address) {
                //fixme
                return null;
            }

            @Override
            public GeoLocationResponse locate(Double latitude, Double longitude) {
                //fixme
                return null;
            }
        };
    }

    @Bean
    public IPAddressIntelligenceService ipAddressIntelligenceService(CasConfigurationProperties casConfigurationProperties){
        return new RestfulIPAddressIntelligenceService(casConfigurationProperties.getAuthn().getAdaptive());
    }

    @Bean
    public AdaptiveAuthenticationPolicy adaptiveAuthenticationPolicy(GeoLocationService geoLocationService,IPAddressIntelligenceService ipAddressIntelligenceService
            ,CasConfigurationProperties casConfigurationProperties){
        return new DefaultAdaptiveAuthenticationPolicy(geoLocationService,ipAddressIntelligenceService,casConfigurationProperties.getAuthn().getAdaptive());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
